#include "Common.h"
#include "SceneManager.h"
#include "Scene.h"
#include "Camera.h"
#include "OctreeScene.h"
#include "RenderView.h"
#include "RenderQueue.h"
#include "RenderQueueGroup.h"
#include "RenderStatus.h"
#include "SceneRenderTargets.h"
#include "RenderWindow.h"

//------------------------------------------
SceneManager::SceneManager(const std::string& name)
	: mName(name)
	, mScene(NULL)
{
	mScene = new Scene(this, MAX_WORLD_SIZE * 0.5f);
}
//------------------------------------------
SceneManager::~SceneManager(void)
{
	if (mScene) delete mScene;
}
//------------------------------------------
void SceneManager::Update(float elapsedTime)
{
	if (mScene)
		mScene->Update(elapsedTime);
}
//------------------------------------------
void SceneManager::Render(Camera* camera, RenderTarget* renderTarget)
{
	RenderView view(mScene, camera, renderTarget);

	InitView(&view);
	
	SceneRenderTargets::Instance().Allocate(view.ViewWidth, view.ViewHeight);
	
	// do we need clear here.
	Clear(true, 0xFF0000FF, true, 1.0f, false, 0);

	for (int group = 0; group < RenderQueue::ERQG_Max; group++)
		RenderObjects(group, &view);
}
//------------------------------------------
void SceneManager::InitView(RenderView* view)
{
	Camera* camera = view->CameraPtr;
	camera->setAspect((float)view->ViewWidth / view->ViewHeight);

	// init the view visible map.
	view->VisibilityMap.Init(false, view->ScenePtr->getRenderableList().size());

	// iterator the scene octree and setup the visible bits.
	for(SceneOctree::TConstIterator it(*view->ScenePtr->getSceneOctree()); it.HasPendingNodes(); it.Advance())
	{
		const SceneOctree::FNode& node = it.GetCurrentNode();
		const FOctreeNodeContext& context = it.GetCurrentContext();

		// Find children of this octree node that may contain relevant primitives.
		FOREACH_OCTREE_CHILD_NODE(ChildRef)
		{
			if (!node.HasChild(ChildRef))
				continue;

			// Check that the child node is in the frustum for at least one view.
			const FOctreeNodeContext childContext = context.GetChildContext(ChildRef);
			if (camera->Visible(childContext.Bounds))
				it.PushChild(ChildRef);
		}

		// Find the primitives in this node that are visible.
		const SceneOctree::ElementArrayType& elements = node.GetElements();
		for (SceneOctree::ElementConstIt eIt(elements.begin()), eEnd(elements.end()); eIt != eEnd; eIt++)
		{
			const OctreeNodeInfoCompact& nodeInfoCompact = *eIt;
			SceneNode* sceneNode = nodeInfoCompact.TreeNode;
			if (!sceneNode->getVisible() || !camera->Visible(sceneNode->getBounds()))
				continue;

			// if there is just one object for scene node
			bool needCheckindividual = sceneNode->getObjectNum() > 1;
			SceneNode::ObjectIterator objIt = sceneNode->getObjectIterator();
			while (objIt.hasMoreElements())
			{
				MovableObject* movableObject = objIt.getNext();
				if (!movableObject->getVisible())
					continue;

				if (!needCheckindividual || camera->Visible(movableObject->getWorldAABB()))
					movableObject->AddToView(view);
			}
		}
	}
}
//------------------------------------------
void SceneManager::RenderObjects(int group, RenderView* view)
{
	//RenderDepthPass(group, view);

	RenderBasePass(group, view);

	RenderLightingPass(group, view);

	RenderTransparents(group, view);

	RenderPostprocess(group, view);
}
//------------------------------------------
void SceneManager::RenderDepthPass(int group, RenderView* view)
{
	RenderQueueGroup* renderGroup = view->ScenePtr->getRenderQueue()->GetGroup(group);
	if (renderGroup == NULL)
		return;

	renderGroup->getDepthDrawList().DrawVisible(view, view->VisibilityMap);
}
//------------------------------------------
void SceneManager::RenderBasePass(int group, RenderView* view)
{
	RenderQueueGroup* renderGroup = view->ScenePtr->getRenderQueue()->GetGroup(group);
	if (renderGroup == NULL)
		return;

	// disable alpha blending.
	SetBlendState();

	// enable depth test.
	SetDepthState();

	renderGroup->getBasePassDrawList().DrawVisible(view, view->VisibilityMap);
}
//------------------------------------------
void SceneManager::RenderLightingPass(int group, RenderView* view)
{
}
//------------------------------------------
void SceneManager::RenderTransparents(int group, RenderView* view)
{
}
//------------------------------------------
void SceneManager::RenderPostprocess(int group, RenderView* view)
{
}
//------------------------------------------